Skip to content

Fix callbacks double-registered when app file is loaded by import string#3883

Open
T4rk1n wants to merge 1 commit into
devfrom
fix/double-register
Open

Fix callbacks double-registered when app file is loaded by import string#3883
T4rk1n wants to merge 1 commit into
devfrom
fix/double-register

Conversation

@T4rk1n

@T4rk1n T4rk1n commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

When the app module runs as a script, a server that loads it by import string (e.g. uvicorn.run("app:server", reload=True)) executes the same file twice in the worker process: multiprocessing spawn re-runs it as mp_main, then the import string imports it again under its real name. Both passes run the @callback decorators, duplicating every spec in _dash-dependencies and triggering "Duplicate callback outputs" errors in the renderer.

Dash() now pre-registers the running main module in sys.modules under its canonical import name (only when that name resolves to the same file and isn't already imported), so the second import reuses the already-executed module instead of re-executing the file.

Fixes #3818

When the app module runs as a script, a server that loads it by import
string (e.g. uvicorn.run("app:server", reload=True)) executes the same
file twice in the worker process: multiprocessing spawn re-runs it as
__mp_main__, then the import string imports it again under its real
name. Both passes run the @callback decorators, duplicating every spec
in _dash-dependencies and triggering "Duplicate callback outputs"
errors in the renderer.

Dash() now pre-registers the running main module in sys.modules under
its canonical import name (only when that name resolves to the same
file and isn't already imported), so the second import reuses the
already-executed module instead of re-executing the file.

Fixes #3818

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jul 7, 2026

Copy link
Copy Markdown

@camdecoster camdecoster left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a couple of suggestions. The CHANGELOG entry is missing the PR number.

Comment thread dash/dash.py
):
sys.modules[import_name] = module
except (ImportError, ValueError, OSError):
pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should a warning be logged here?

Comment thread CHANGELOG.md
## [Unreleased]

## Fixed
- [](https://github.com/plotly/dash/pull/) Fix callbacks being registered twice when running the app file as a script with a server that loads it by import string, e.g. `uvicorn.run("app:server", reload=True)` with `backend="fastapi"`. The spawned worker re-executes the main module as `__mp_main__` and the import string then executed the same file a second time, duplicating every callback in `_dash-dependencies` and triggering `Duplicate callback outputs` errors in the renderer. `Dash()` now pre-registers the running main module in `sys.modules` under its canonical import name so the second import reuses it instead of re-executing the file. Fixes [#3818](https://github.com/plotly/dash/issues/3818).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entry is pretty verbose. I'd suggest trimming it a bit.

Suggested change
- [](https://github.com/plotly/dash/pull/) Fix callbacks being registered twice when running the app file as a script with a server that loads it by import string, e.g. `uvicorn.run("app:server", reload=True)` with `backend="fastapi"`. The spawned worker re-executes the main module as `__mp_main__` and the import string then executed the same file a second time, duplicating every callback in `_dash-dependencies` and triggering `Duplicate callback outputs` errors in the renderer. `Dash()` now pre-registers the running main module in `sys.modules` under its canonical import name so the second import reuses it instead of re-executing the file. Fixes [#3818](https://github.com/plotly/dash/issues/3818).
- [3883](https://github.com/plotly/dash/pull/3883) Fix callbacks being registered twice when running the app file as a script with a server that loads it by import string, e.g. `uvicorn.run("app:server", reload=True)` with `backend="fastapi"`. The spawned worker re-executes the main module as `__mp_main__` and the import string then executed the same file a second time, duplicating every callback in `_dash-dependencies` and triggering `Duplicate callback outputs` errors in the renderer. `Dash()` now pre-registers the running main module in `sys.modules` under its canonical import name so the second import reuses it instead of re-executing the file. Fixes [#3818](https://github.com/plotly/dash/issues/3818).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Callbacks double-registered when using uvicorn --reload under backend="fastapi"

2 participants